package com.concurrent.concurrentdemo.lock;

import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.LockSupport;

public class QueueLock {
    // 是否上锁的状态
    private final AtomicBoolean locked = new AtomicBoolean(false);
    // 存放竞争的线程
    private final Queue<Thread> waiters = new ConcurrentLinkedDeque<>();

    public void lock() {
        boolean wasInterrupted = false;
        Thread current = Thread.currentThread();
        waiters.add(current);
        // 只有队列首部的线程才能获取锁
        while (waiters.peek() != current || !locked.compareAndSet(false, true)) {
            LockSupport.park(this);
            if (Thread.interrupted()) {
                wasInterrupted = true;
            }
        }
        waiters.remove();
        if (wasInterrupted) {
            current.interrupt();
        }
    }

    public void unlock() {
        // 按照正常的执行顺序，先lock后unlock，就只有一个线程执行到unlock方法
        locked.set(false);
        LockSupport.unpark(waiters.peek());
    }

    public static int num = 0;

    public static void main(String[] args) throws InterruptedException {
        QueueLock lock = new QueueLock();
        CountDownLatch countDownLatch = new CountDownLatch(10);
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                lock.lock();
                for (int j = 0; j < 100000; j++) {
                    num++;
                }
                countDownLatch.countDown();
                lock.unlock();
            }).start();
        }
        countDownLatch.await();
        System.out.println(num);
    }
}
